#include "c_vm.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <stdint.h>
#include "../common_defs.h"

// 添加头文件解决open、close、read的隐式声明问题
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#else
#include <unistd.h>
#include <fcntl.h>
#endif

char** vm_argv = NULL;
int vm_argc = 0;

#define int intptr_t // 兼容性定义

// 释放虚拟机资源
void vm_free() {
    if (text_start) {
        free(text_start);
        text_start = NULL;
    }
    if (data_start) {
        free(data_start);
        data_start = NULL;
    }
    if (stack_start) {
        free(stack_start);
        stack_start = NULL;
    }
    if (symbols_start) {
        free(symbols_start);
        symbols_start = NULL;
    }
    if(data_start){
        free(data_start);
        data_start = NULL;
    }
    if(old_src){
        free(old_src);
        old_src = NULL;
    }
}

// 获取代码段指针初始地址
intptr_t* vm_get_text_start() {
    return text_start;
}

// 获取数据段指针初始地址
char* vm_get_data_start() {
    return data_start;
}

// 获取栈指针初始地址
intptr_t* vm_get_stack_start() {
    return stack_start;
}

// 获取符号表指针初始地址
intptr_t* vm_get_symbols_start() {
    return symbols_start;
}

char* vm_get_data(){
    return data;    
}

void vm_set_data(char* xdata){
    data = xdata;
}

// 修改eval函数返回类型为intptr_t
intptr_t eval(){
    vm_running_env_init();
    int op, *tmp;
    while (1) {
        op = *pc++;
        if (op == IMM) {
            ax = *pc++;
        }
        else if (op == LC) {
            ax = *(char *)ax;
        }
        else if (op == LI) { // 读出ax中地址值
            ax = *(int *)ax;
        }
        else if (op == SC) {
            ax = *(char *)*sp++ = ax;
        }
        else if (op == SI) { // 为变量赋值
            *(int *)*sp++ = ax;
        }
        else if (op == PUSH) { // 将寄存器ax值压入栈中(ax可以保存地址或值)
            *--sp = ax;
        }
        else if (op == JMP) {
            pc = (int *)*pc;
        }
        else if (op == JZ) {
            pc = ax ? pc + 1 : (int *)*pc;
        }
        else if (op == JNZ) {
            pc = ax ? (int *)*pc : pc + 1;
        }
        else if (op == JFZ){
            pc = ax ? (int*)*(pc + 1) : (int *)*pc;
        }
        else if (op == CALL) {
            *--sp = (int)(pc+1); // 当我们从子函数中返回时，程序需要回到跳转之前的地方继续运行，这就需要事先将这个位置信息存储起来
            pc = (int *)*pc;
        }
        else if (op == ENT) {
            *--sp = (int)bp;
            bp = sp;
            sp = sp - *pc++;
        }
        else if (op == ADJ) {  // 清理形参
            sp = sp + *pc++;
        }
        else if (op == LEV) {
            sp = bp;  // 清理局部变量
            bp = (int *)*sp++; // 释放栈帧
            pc = (int *)*sp++; // 恢复跳转位置
        }
        else if (op == LEA) {  // 把局部变量的地址保存到ax
            ax = (int)(bp + *pc++);
        }
        else if (op == OR) {
            ax = *sp++ | ax;
        }
        else if (op == XOR) {
            ax = *sp++ ^ ax;
        }
        else if (op == AND) {
            ax = *sp++ & ax;
        }
        else if (op == EQ) {
            ax = *sp++ == ax;
        }
        else if (op == NE) {
            ax = *sp++ != ax;
        }
        else if (op == LT) {  // 循环中小于比较
            ax = *sp++ < ax;
        }
        else if (op == LE) {
            ax = *sp++ <= ax;
        }
        else if (op == GT) {
            ax = *sp++ > ax;
        }
        else if (op == GE) {
            ax = *sp++ >= ax;
        }
        else if (op == SHL) {
            ax = *sp++ << ax;
        }
        else if (op == SHR) {
            ax = *sp++ >> ax;
        }
        else if (op == ADD) {
            ax = *sp++ + ax;
        }
        else if (op == SUB) {
            ax = *sp++ - ax;
        }
        else if (op == MUL) {
            ax = *sp++ * ax;
        }
        else if (op == DIV) {
            ax = *sp++ / ax;
        }
        else if (op == MOD) {
            ax = *sp++ % ax;
        }
        else if (op == EXIT) {
            printf("exit(%lld)\n", *sp);
            return *sp;
        }
        else if (op == OPEN) {
            ax = open((char *)sp[1], (int)sp[0]);
        }
        else if (op == CLOS) {
            ax = close((int)*sp);
        }
        else if (op == READ) {
            ax = read((int)sp[2], (char *)sp[1], (int)*sp);
        }
        else if (op == PRTF) {
            tmp = sp + pc[1];
            ax = printf((char *)tmp[-1], tmp[-2], tmp[-3], tmp[-4], tmp[-5], tmp[-6]);
            fflush(stdout);
        }
        else if (op == SCANF) {
            tmp = sp + pc[1];
            ax = scanf((char *)tmp[-1], tmp[-2], tmp[-3], tmp[-4], tmp[-5], tmp[-6]);
        }
        else if (op == MALC) {
            ax = (int)malloc(*sp);
            printf("malloc addr: %p\n", ax);
        }
        else if (op == MSET) {
            ax = (int)memset((char *)sp[2], sp[1], *sp);
        }
        else if (op == MCMP) {
            ax = memcmp((char *)sp[2], (char *)sp[1], *sp);
        }
        else if (op == FREE) {
            free((char *)*sp);
            printf("free addr: %p\n", *sp);
        }
        else {
            printf("unknown instruction:%lld\n", op);
            return -1;
        }
    }
    return 0;
}



// 修改vm_running_env_init函数返回类型为intptr_t
intptr_t vm_running_env_init(){
    int *tmp;
    if (!(pc = (int *)idmain)) {  // 在program把main在text中的入口地址填入了Vlaue中，赋值给pc就可以从第一条指令开始执行了
        printf("main() not defined\n");
        return -1;
    }

    // setup stack
    sp = (int *)((int)stack + poolsize);

    /*新符号表打印*/
        printf("text: %p\n,\
            data: %p\n,\
           sp: %p\n,\
           bp: %p\n,\
           pc: %p\n,\
           symbols_start: %p\n",\
           text_start, data_start, sp, bp, pc, scope_stack->stack[0]); // scope_stack->stack只表示栈顶指针的地址，*(scope_stack->stack)才是栈顶指针指向的地址。即stack[0]
    *--sp = EXIT; // call exit if main returns
    *--sp = PUSH; tmp = sp;
    *--sp = vm_argc;
    *--sp = (int)vm_argv;
    *--sp = (int)tmp;
    
    return 0;
}

#undef int // 撤销宏定义 